package no.ntnu.idi.deid.patternmatching.search;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.lucene.index.Term;
import org.apache.lucene.search.TermQuery;

import no.ntnu.idi.deid.config.FilePaths;
import no.ntnu.idi.deid.decision.validators.DateValidator;
import no.ntnu.idi.deid.decision.validators.PersonNumberValidator;
import no.ntnu.idi.deid.decision.validators.PhoneFaxNumberValidator;
import no.ntnu.idi.deid.decision.validators.TimeValidator;
import no.ntnu.idi.deid.documentunits.Sentence;
import no.ntnu.idi.deid.documentunits.Token;
import no.ntnu.idi.deid.patternmatching.search.dictionary.lucene.IndexBuilder;
import no.ntnu.idi.deid.patternmatching.search.dictionary.lucene.SearchField;
import no.ntnu.idi.deid.patternmatching.search.dictionary.medicalcodes.*;
import no.ntnu.idi.deid.patternmatching.search.regularexpression.RegularExpressionDatabase;
import no.ntnu.idi.deid.searchresultunits.CategoryTag;
import no.ntnu.idi.deid.searchresultunits.Tag;

public class TokenSearch{
	
	private Token token;
	
	public TokenSearch(Token token) {
		this.token = token;
	}
			
	public void searchInRegularExpressionDatabase() {
		Set<CategoryTag> tagSet = RegularExpressionDatabase.getInstance().search(token);
		Iterator<CategoryTag> it = tagSet.iterator();
		while(it.hasNext()) {
			Tag categoryTag = it.next().getTag();
			switch (categoryTag) {
			case DATE:
				checkDateOrPNR(categoryTag);
				break;
			case NATIONALIDENTITYNUMBER:
				if (PersonNumberValidator.isTokenValidPNR(token)) {
					token.addTag(categoryTag);
				}
				break;
			case ZIPCODE:
				addYearTag();
				addZipCodeTag();
				break;
			case PART:
				phoneNumberCheck();
				if(!(tagSet.contains(new CategoryTag(Tag.TLFNUMBER)) || token.containsCategoryTag(Tag.TLFNUMBER))) {
					timeCheck();
				}
				break;
			case MONTH:
				if(token.hasNext()) {
					if(DateValidator.isYear(token.next())){
						token.next().addTag(Tag.YEAR);
					}
				}
				token.addTag(categoryTag);
				break;
			default:
				token.addTag(categoryTag);
				break;
			}				
		}
	}

	private void phoneNumberCheck() {
		List<Token> list = new ArrayList<Token>();
		Sentence sentence = token.getSentence();
		for(Token iteratorToken: sentence){
			if(iteratorToken.getIndex() >= token.getIndex()) {
				if(Token.isNumber(iteratorToken.getStripped()) || iteratorToken.equals("+47")) {
					list.add(iteratorToken);
				}
				else {
					break;
				}
			}
		}
		PhoneFaxNumberValidator.checkPhoneOrFax(list);
	}

	private void addYearTag() {
		if (DateValidator.isValidYear(token, 1900, 2140)) {
			token.addTag(Tag.YEAR);
		}
	}

	private void addZipCodeTag() {
		CategoryTag zipCodeTag = Zip_Code.searchInZipcodes(token);
		if (zipCodeTag != null) {
			token.addTag(Tag.ZIPCODE);
		}
	}

	private void timeCheck() {
		if(token.hasNext()) {
			if(TimeValidator.validateTimeFromTwoTokens(token, token.next())) {
				token.addTag(Tag.TIME);
				token.next().addTag(Tag.TIME);
			}
		}
	}

	private void checkDateOrPNR(Tag tag) {
		if(token.hasNext()) {
			if(PersonNumberValidator.checkTwoTokensForValidPNR(token, token.next())) {
				token.addTag(Tag.NATIONALIDENTITYNUMBER);
				token.next().addTag(Tag.NATIONALIDENTITYNUMBER);
			}
		}
		if (DateValidator.isValidDate(token) && !token.containsCategoryTag(Tag.NATIONALIDENTITYNUMBER)) {
			token.addTag(tag);
		}
	}
	
	public void wordSearchInDictionary() {
		String word = token.getStripped().toLowerCase();
		TermQuery termQuery = new TermQuery(new Term(IndexBuilder.FIELD_CONTENTS, word));
		SearchField searchfield;
		Set<CategoryTag> resultSet = Collections.emptySet();
		try {
			searchfield = SearchField.generateStandardSearchField(FilePaths.getTermIndexDirectory());
			resultSet = searchfield.searchAndReturnSet(termQuery);
			searchfield.closeReader();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if(resultSet.contains(new CategoryTag(Tag.MESH))) {
			resultSet.add(MESH_Codes.searchExactDescription(token.getStripped()));
		}
		token.addSet(resultSet);
	}
	
	public void searchInMedicalCodes() {
		token.addTag(NCMP_Codes.searchNCMPCode(token));
		token.addTag(Medical_Keyword.searchInMedicalKeywords(token));
		token.addTag(Zip_Code.searchInZipcodes(token));
		token.addTag(NCSP_Codes.searchNCSPCode(token));
		token.addTag(ATC_Codes.searchATC(token));
		token.addTag(ICPC2_Codes.searchICPC2Code(token));
		token.addTag(Snomed_Elements.searchInSnomedElements(token));
		token.addTag(ICD10_Codes.searchICD10Code(token));
		token.addTag(MESH_Codes.searchMeshCodes(token));
		token.addTag(NCRP_codes.searchNCRPCode(token));
	}
}
